package com.zp.qualitypractice.list;

import android.content.Context;
import android.graphics.Rect;
import android.support.annotation.Nullable;
import android.support.v4.widget.ViewDragHelper;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

import com.zp.qualitypractice.list.footer.FooterView;
import com.zp.qualitypractice.list.header.HeaderView;
import com.zp.qualitypractice.SwipeLayout.SwipeItemView;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by izp on 2017/4/25.
 */

public class RefreshLoadSwipeLayout extends RecyclerView {
    private boolean mPullRefreshAble = true;//可下拉刷新
    private boolean mPullLoadAble = true;//可上拉加载
    private boolean mIsLoading = false;//刷新中
    private boolean mNoMoreData = false;//服务器返回了没有更多数据的标识
    private boolean mIsChildHandle;
    private float mStartX;//全局保存触摸点位置
    private float mStartY;
    private float mDistanceX;//全局保存手指移动的距离.这两个都是侧滑删除时拦截滑动只实现横向滑动
    private float mDistanceY;
    private final float  mEffectTouchDistance = 4f;
    private float mLastY = -1;

    private static final int TYPE_REFRESH_HEADER = -5;
    private static final int TYPE_NORMAL = 0;
    private static final int TYPE_FOOTER = -3;

    private static final float DRAG_RATE = 2;//阻率

    private List<View> mHeaderViews = new ArrayList<>();
    private List<View> mFooterViews = new ArrayList<>();
    private static List<Integer> sHeaderTypes = new ArrayList<>();

    private HeaderView mHeaderView;
    private View mEmptyView;//adapter没有数据的时候显示,类似于listView的emptyView
    private Rect mTouchFrame;//item的轮廓,用于计算触摸到第几个item了
    private View mLastTouchItem;


    private WrapAdapter mWrapAdapter;

    private OnPullLoadListener mOnPullLoadListener;

    public RefreshLoadSwipeLayout(Context context) {
        super(context);
        init();
    }

    public RefreshLoadSwipeLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public RefreshLoadSwipeLayout(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init(){
        if (mPullRefreshAble){
            mHeaderView = new HeaderView(getContext());
            mHeaderViews.add(0,mHeaderView);
        }
        if (mPullLoadAble){
            FooterView footerView = new FooterView(getContext());
            mFooterViews.clear();
            mFooterViews.add(footerView);
            mFooterViews.get(0).setVisibility(GONE);
        }
    }

    /**
     * @param screenState
     * 当滚动状态改变时
     */
    @Override
    public void onScreenStateChanged(int screenState) {
        super.onScreenStateChanged(screenState);//覆写了也没关系，父类什么也没做
        /*
        1.  SCROLL_STATE_IDLE 滑动后静止
        2.  SCROLL_STATE_FLING 手指离开屏幕后，惯性滑动
        3.  SCROLL_STATE_TOUCH_SCROLL 手指在屏幕上滑动
        一般执行顺序为：3---》2---》1
        * */
        if (mPullLoadAble && screenState==RecyclerView.SCROLL_STATE_IDLE && !mIsLoading
                && null!=mOnPullLoadListener){
            ///可上拉加载，滑动后静止，不在加载中，同时刷新监听器已经初始化
            LayoutManager layoutManager = getLayoutManager();
            int lastVisiblePosition ;
            if (layoutManager instanceof GridLayoutManager){
                lastVisiblePosition = ((GridLayoutManager) layoutManager).findLastVisibleItemPosition();
            }else if (layoutManager instanceof StaggeredGridLayoutManager){
                int[] into =((StaggeredGridLayoutManager) layoutManager).findLastVisibleItemPositions(
                        new int[((StaggeredGridLayoutManager) layoutManager).getSpanCount()]
                );
                lastVisiblePosition = findMax(into);//找到into中的最大值
            }else{
                lastVisiblePosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
            }
            /*
            * getItemCount()这个方法是获取所有的条目数
                getChildCount()是获取可视的条目数*/
            if (layoutManager.getChildCount()>0 &&
                    lastVisiblePosition >= layoutManager.getItemCount()-1 &&
                    layoutManager.getItemCount()>layoutManager.getChildCount() &&
                    !mNoMoreData && mHeaderView.getState()< HeaderView.STATE_REFRESHING){
                    //列表可见条目大于0，列表最后一个可见item比item总数-1要大或者=（实际上只可能等于，等于的时候就到底了）
                    //所有条目要比可见条目要大（等于都不可以么？），同时当前服务器状态是有数据可取，并且列表的状态是准备刷新和正常状态
                View view =mFooterViews.get(0);
                if (view instanceof FooterView){
                    ((FooterView) view).setState(FooterView.STATE_LOADING);
                }else {
                    view.setVisibility(View.VISIBLE);
                }
                mOnPullLoadListener.onLoading();
            }
        }
    }

    @Override
    public void setAdapter(Adapter adapter) {
        super.setAdapter(adapter);
    }

    @Override
    public boolean onTouchEvent(MotionEvent e) {
        if (mLastY==-1){
            mLastY =e.getRawY();//获取手指在屏幕上的绝对Y值
        }
        switch (e.getAction()){
            case MotionEvent.ACTION_DOWN:
                mLastY= e.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                final float deltaY = e.getRawY() - mLastY;
                mLastY = e.getRawY();
                if (isOnTop() && mPullRefreshAble) {//headerView的getParent!=null就能判断
                    mHeaderView.onMove(deltaY/DRAG_RATE);//DragRate拖动阻尼,
//                    如果移动，就把动态设置header高度，然后
                    if (mHeaderView.getVisibleHeight()>0 && mHeaderView.getState() <HeaderView.STATE_REFRESHING){
                        return false;
                    }
                }
                break;
            default://只要松手，不管是什么事件，都复位
                mLastY = -1;
                if (isOnTop() && mPullRefreshAble){
                    if (mHeaderView.releaseAction()) {//调用释放方法，重置高度，重置失败时返回true，这个时候执行正在刷新方法
                        if (mOnPullLoadListener != null) {
                            mOnPullLoadListener.onRefreshing();
                        }
                    }
                }
                break;
        }
        return super.onTouchEvent(e);
    }
    /**
     * @param ev
     * @return
     * 用于处理侧滑菜单,拦截触摸事件主要是为了处理横向滑动
     */
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        int action = ev.getActionMasked();
        if (action ==MotionEvent.ACTION_DOWN){
            mIsChildHandle = false;//这个IsCildHandle到底是什么意思还没搞明白
//            记录手指按下的位置
            mStartX = ev.getX();//这个是记录View相对位置啊,之前看很多都是记录绝对位置?
            mStartY = ev.getY();
            mDistanceX = 0;
            mDistanceY = 0;
//            获取手指点击的那个View,这个相对位置就说得通了,有可能相对位置要比绝对位置范围要大!
            int position = pointToPosition((int) mStartX, (int) mStartY);
            mLastTouchItem = getChildAt(position);
            if (hasChildOpen()){
                // 如果触摸的不是打开的那个View, 关闭所有View，并且拦截所有事件
                if (mLastTouchItem != null && mLastTouchItem instanceof SwipeItemView
                        && ((SwipeItemView) mLastTouchItem).isOpen()) {
                    mIsChildHandle = true; // 将事件交给child！
                } else {
                    closeAllSwipeItem();
                    return false;
                }
            }
        }
        // 禁用多点触控
        if (action == MotionEvent.ACTION_POINTER_DOWN) {
            return false;//不派发事件,这个还是不太好,多点应该还是要处理一下
        }
        return super.dispatchTouchEvent(ev);
    }


    /**
     * @param e
     * @return
     * 处理和侧滑菜单的冲突
     */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent e) {
        // 如果竖向滑动，拦截，否则不拦截。
        int action = e.getActionMasked();
        switch (action){
            case MotionEvent.ACTION_MOVE:
                // 获取当前手指位置
                float endY = e.getY();
                float endX = e.getX();
                mDistanceX = Math.abs(endX - mStartX);//这个是dispatchTouchEvent的startX
                mDistanceY = Math.abs(endY - mStartY);
                // 如果child已经持有事件，那么不拦截它的事件，直接return false；
                if (mIsChildHandle) {
                    return false;
                }
                // 如果X轴位移大于Y轴位移，那么将事件交给child处理。
                if (mDistanceX > mEffectTouchDistance && mDistanceX > mDistanceY) {
                    mIsChildHandle = true;
                    return false;
                }
                break;
            case MotionEvent.ACTION_UP:
//                离开屏幕的事件为毛也要拦截
                if (mLastTouchItem != null && mLastTouchItem instanceof SwipeItemView) {
                    SwipeItemView swipeItemView = (SwipeItemView)mLastTouchItem;
                    if (swipeItemView.isOpen() && swipeItemView.getState() != ViewDragHelper.STATE_DRAGGING) {//这个state是onViewDragStateChanged回调时传入的
//                        IDLE,DRAGGING,SETTING[自动滚动时]，三个状态,view当前不是正被抓住
                        if (mDistanceX < mEffectTouchDistance && mDistanceY < mEffectTouchDistance) {
                            //如果垂直和水平的滑动距离都不达标，那么关闭
                            swipeItemView.closeMenu();
                        }
                        Rect rect = swipeItemView.getMenuViewRect();
                        // 如果不是点击在菜单上，拦截点击事件。
                        if (!(mStartX > rect.left && mStartX < rect.right &&
                                mStartY > swipeItemView.getTop() && mStartY< swipeItemView.getBottom())) {
                            return true;  // return true，拦截Item点击事件, 但是菜单能接收到。
                        }
                    }
                }
                break;
        }
        return super.onInterceptTouchEvent(e);
    }

    public boolean isTop(){//这个isTop判断有些奇怪,判断header存在,同时headerView的parent存在?就能判断是否在顶部?
        return !(mHeaderViews == null || mHeaderViews.isEmpty()) && mHeaderViews.get(0).getParent() != null;
    }

    /**
     * @param x
     * @param y
     * @return
     */
    private int pointToPosition(int x, int y) {

        if (mTouchFrame == null) {
            mTouchFrame = new Rect();
        }
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {//循环遍历所有的childView
            View child = getChildAt(i);
            if (child.getVisibility() == VISIBLE) {
                child.getHitRect(mTouchFrame);//获取childView 的轮廓,如果他包含触摸的x,y那么就返回当前的item的序号
                if (mTouchFrame.contains(x, y)) {
                    return i;
                }
            }
        }
        return -1;
    }
    /**
     * 是否还有条目打开
     *
     * @return
     */
    private boolean hasChildOpen() {
        final int count = getChildCount();
        for (int i = count - 1; i >= 0; i--) {//遍历child
            final View child = getChildAt(i);
            if (child != null && child instanceof SwipeItemView) {
                if (((SwipeItemView) child).isOpen()) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 关闭所有侧滑按钮
     */
    private void closeAllSwipeItem() {
        final int count = getChildCount();
        for (int i = count - 1; i >= 0; i--) {
            final View child = getChildAt(i);
            if (child != null && child instanceof SwipeItemView) {
                ((SwipeItemView) child).closeMenu();
            }
        }
    }

    private int findMax(int[] into) {
        int max = into[0];
        for (int value : into) {
            if (value > max) {
                max = value;
            }
        }
        return max;
    }
    /**
     * 设置刷新和加载更多的监听器
     *
     * @param refreshAndLoadMoreListener 监听器
     */
    public void setRefreshAndLoadMoreListener(OnPullLoadListener refreshAndLoadMoreListener) {
        this.mOnPullLoadListener = refreshAndLoadMoreListener;
    }
    /**
     * 设置刷新完成
     */
    public void refreshComplete() {
        mHeaderView.onRefreshComplete();
    }
    /**
     * 设置加载更多完成
     */
    public void setloadMoreComplete() {
        //设置加载数据为false
        mIsLoading = false;
        View footView = mFooterViews.get(0);
        if (footView instanceof FooterView) {
            ((FooterView) footView).setState(FooterView.STATE_COMPLETE);
        } else {
            footView.setVisibility(View.GONE);
        }
    }
    /**
     * 添加底部布局
     *
     * @param footView
     */
    private void addFootView(FooterView footView) {
        mFooterViews.clear();
        mFooterViews.add(footView);
    }

    /**
     * 是否是顶部
     *
     * @return
     */
    public boolean isOnTop() {
        return !(mHeaderViews == null || mHeaderViews.isEmpty()) && mHeaderViews.get(0).getParent() != null;
    }

    /**
     * 对传入的adapter进行包装
     */
    private class WrapAdapter extends RecyclerView.Adapter<ViewHolder>{
        private RecyclerView.Adapter mAdapter;
        private int mCurrentPosition;
        private int headerPosition = 1;

        public WrapAdapter(Adapter mAdapter) {
            this.mAdapter = mAdapter;
        }

        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            if (viewType == TYPE_REFRESH_HEADER) {
                mCurrentPosition++;//确定onCreateViewholder没添加一个item就调用一次?不多不少?
                return new SimpleViewHolder(mHeaderViews.get(0));
            } else if (mCurrentPosition >= 1 && mCurrentPosition< mHeaderViews.size()) {
                if (viewType == sHeaderTypes.get(mCurrentPosition - 1)) {
                    mCurrentPosition++;
                    return new SimpleViewHolder(mHeaderViews.get(headerPosition++));
                }
            } else if (viewType == TYPE_FOOTER) {
                return new SimpleViewHolder(mFooterViews.get(0));
            }
            return mAdapter.onCreateViewHolder(parent, viewType);
        }

        @Override
        public void onBindViewHolder(ViewHolder holder, int position) {
            if (isHeader(position)) {
                return;
            }
            int adjPosition = position - mHeaderViews.size();
            int adapterCount;
            if (mAdapter != null) {
                adapterCount = mAdapter.getItemCount();
                if (adjPosition < adapterCount) {
                    mAdapter.onBindViewHolder(holder, adjPosition);
                }
            }
        }

        @Override
        public int getItemCount() {
            if (mAdapter != null) {
                return mHeaderViews.size() + mFooterViews.size() + mAdapter.getItemCount();
            } else {
                return mHeaderViews.size() + mFooterViews.size();
            }
        }

        @Override
        public long getItemId(int position) {
            if (mAdapter != null && position >= mHeaderViews.size()) {
                int adjPosition = position - mHeaderViews.size();
                int adapterCount = mAdapter.getItemCount();
                if (adjPosition < adapterCount) {
                    return mAdapter.getItemId(adjPosition);
                }
            }
            return -1;
        }

        @Override
        public int getItemViewType(int position) {
            if (position==0){
                return TYPE_REFRESH_HEADER;
            }
            if (position>=0 && position < mHeaderViews.size()){
                //position大于等于0可以理解,但是小于所有header的size这个有点难以理解了
                //然后position还有自减1,获取上一个position的type?
                return sHeaderTypes.get(position-1);
            }
            if (position<getItemCount() && position>=getItemCount()-mFooterViews.size()){
                //footer的postion肯定是小于所有item的数量的,position是从0开始,
                // 然后但是又大于footer size这点,
                return TYPE_FOOTER;
            }

            if (null==mAdapter){
                if ((position-mHeaderViews.size()) < mAdapter.getItemCount()){
//                    如果当前positon-header的size,剩下从正常0开始的,这个positon小于内部adpter的size
                    return mAdapter.getItemViewType(position-mHeaderViews.size());
                }
            }
            return TYPE_NORMAL;
        }



        @Override
        public void onAttachedToRecyclerView(RecyclerView recyclerView) {
            super.onAttachedToRecyclerView(recyclerView);
            final RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
            if (layoutManager instanceof GridLayoutManager){
                ((GridLayoutManager) layoutManager).setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                    @Override
                    public int getSpanSize(int position) {
                        return ((position>=0 && position < mHeaderViews.size()) || (position<getItemCount() &&
                        position>=getItemCount()-mFooterViews.size()))
                                ? ((GridLayoutManager) layoutManager).getSpanCount() : 1;
                    }
                });
            }
        }

        @Override
        public void onViewAttachedToWindow(ViewHolder holder) {
            super.onViewAttachedToWindow(holder);
            ViewGroup.LayoutParams layoutParams =holder.itemView.getLayoutParams();
            if (null!=layoutParams && layoutParams instanceof StaggeredGridLayoutManager.LayoutParams &&
                    isHeader(holder.getLayoutPosition()) || isFooter(holder.getLayoutPosition())){
                StaggeredGridLayoutManager.LayoutParams sLayoutParams = (StaggeredGridLayoutManager.LayoutParams) layoutParams;
                sLayoutParams.setFullSpan(true);
            }
        }
        @Override
        public void registerAdapterDataObserver(AdapterDataObserver observer) {
            if (mAdapter != null) {
                mAdapter.registerAdapterDataObserver(observer);
            }
        }

        @Override
        public void unregisterAdapterDataObserver(AdapterDataObserver observer) {
            if (mAdapter != null) {
                mAdapter.unregisterAdapterDataObserver(observer);
            }
        }

        public boolean isHeader(int position) {
            return position >= 0 && position < mHeaderViews.size();
        }
        public boolean isFooter(int position) {
            return position < getItemCount() && position >= getItemCount() - mFooterViews.size();
        }
        private class SimpleViewHolder extends RecyclerView.ViewHolder {
            public SimpleViewHolder(View itemView) {
                super(itemView);
            }
        }
    }

    private class DataObserver extends RecyclerView.AdapterDataObserver {
        @Override
        public void onChanged() {
//            super.onChanged();
            Adapter<?> adapter = getAdapter();
            if (adapter != null && mEmptyView != null) {
                int emptyCount = 0;
                if (mPullRefreshAble) {
                    emptyCount++;//空次数计算是什么鬼?
                }
                if (mPullLoadAble){
                    emptyCount++;
                }
                if (adapter.getItemCount() == emptyCount) {
                    //这个itemContent跟Change没有关系啊?change几次 emptyCount会重置啊?
                    mEmptyView.setVisibility(View.VISIBLE);
                    RefreshLoadSwipeLayout.this.setVisibility(View.GONE);
                }else {
                    mEmptyView.setVisibility(View.GONE);
                    RefreshLoadSwipeLayout.this.setVisibility(View.VISIBLE);
                }
            }
            if (mWrapAdapter != null) {
                mWrapAdapter.notifyDataSetChanged();
            }
        }

        @Override
        public void onItemRangeInserted(int positionStart, int itemCount) {
            mWrapAdapter.notifyItemRangeInserted(positionStart, itemCount);
        }

        @Override
        public void onItemRangeChanged(int positionStart, int itemCount) {
            mWrapAdapter.notifyItemRangeChanged(positionStart,itemCount);
        }

        @Override
        public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
            mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount, payload);
        }

        @Override
        public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
            mWrapAdapter.notifyItemMoved(fromPosition, toPosition);
        }

        @Override
        public void onItemRangeRemoved(int positionStart, int itemCount) {
            mWrapAdapter.notifyItemRangeRemoved(positionStart, itemCount);
        }
    }
}
